[org 0x7c00] ; 本程序代码加载到内存的位置是0x7c00

; 设置屏幕模式为文本模式，清除屏幕
mov ax, 3
int 0x10 ; BIOS系统调用，显示器相关功能
; 初始化段寄存器，如果不初始化的话一些虚拟机会报错，如vmware
mov ax, 0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00 ; 初始化栈到0x7c00的位置

; xchg bx, bx ; 交换数据指令，bochs特有的魔数断点，测试用，在bochs的配置文件中的magic_break: enabled=1开启，就会在启动执行到这条指令时会产生断点，便于观察，

mov si, booting
call print

; 阻塞在当前行，$表示当前行
jmp $  ; 反复跳转到当前行

booting:
    db "booting on...", 10, 13, 0 ; 分别是 \n(换行) \r（将光标移动到气势位置） 0（字符串结束）

print:
    mov ah, 0x0e ; 设置的前置条件
    ; 创建一个循环打印
    .next:
        mov al, [si] ; 间接寻址，将si指向的字符放入al
        cmp al, 0 ; 和0比较，如果是0则表示字符串最后一个字符，循环结束
        jz .return ; jump if zero，当零标志位ZF为1时，执行跳转操作， cmp的两个操作数的值相等（相减为0），ZF标志位会被设置为1，则跳转到.return。
        ;jz指令的另一种写法是je指令，即jump if equal，它的作用与jz指令完全相同
        int 0x10  ; 如果不是最后一个0则要调用0x10中断bios的打印功能继续打印
        inc si ; 将si+1
        jmp .next
    .return
    ret

; 主引导扇区共512字节，最后两个字节固定是0x55 0xaa，所以需要从上面代码结束位置开始到第510字节全部填充0
; 重复510-(当前行位置$-程序开始位置$$)次数，对应的字节全设置为0
times 510 - ($ - $$) db 0

; 设置两个字节的内容，主引导扇区的最后两个字节必须是0x55 0xaa
; dw 0xaadd  ; 也可以写成这样，小端存储
db 0x55, 0xaa

; 编译 nasm -f bin boot.asm -o boot.bin